package com.xxl.sso.core.filter;

import com.alibaba.fastjson.JSON;
import com.xxl.sso.core.conf.Conf;
import com.xxl.sso.core.entity.ReturnT;
import com.xxl.sso.core.login.SsoWebLoginHelper;
import com.xxl.sso.core.path.impl.AntPathMatcher;
import com.xxl.sso.core.user.XxlSsoUser;
import com.xxl.sso.core.util.CacheManager;
import com.xxl.sso.core.util.CookieUtil;
import com.xxl.sso.core.util.HttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * web sso filter
 *
 * @author xuxueli 2018-04-03
 */
public class XxlSsoLoginFilter extends HttpServlet implements Filter {
    private static Logger logger = LoggerFactory.getLogger(XxlSsoLoginFilter.class);

    private static final AntPathMatcher antPathMatcher = new AntPathMatcher();

    private String ssoServer;
    private String logoutPath;
    private String excludedPaths;
    private String domain;
    private int localCacheTime = 0;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

        ssoServer = filterConfig.getInitParameter(Conf.SSO_SERVER);
        logoutPath = filterConfig.getInitParameter(Conf.SSO_LOGOUT_PATH);
        excludedPaths = filterConfig.getInitParameter(Conf.SSO_EXCLUDED_PATHS);
        domain = filterConfig.getInitParameter(Conf.SSO_DOMAIN);
        String localCacheTimeStr = filterConfig.getInitParameter(Conf.SSO_LOCAL_CACHE_TIME);
        if (localCacheTimeStr != null&&!"".equals(localCacheTimeStr)) {
            logger.info("session local cache time {}",localCacheTimeStr);
            localCacheTime = Integer.parseInt(localCacheTimeStr);
        }
        logger.info("XxlSsoWebFilter init.");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        // make url
        String servletPath = req.getServletPath();

        // excluded path check
        if (excludedPaths != null && excludedPaths.trim().length() > 0) {
            for (String excludedPath : excludedPaths.split(",")) {
                String uriPattern = excludedPath.trim();

                // 支持ANT表达式
                if (antPathMatcher.match(uriPattern, servletPath)) {
                    // excluded path, allow
                    chain.doFilter(request, response);
                    return;
                }

            }
        }

        // logout path check
        if (logoutPath != null
                && logoutPath.trim().length() > 0
                && logoutPath.equals(servletPath)) {

            // remove cookie
            SsoWebLoginHelper.removeSessionIdByCookie(req, res);

            // redirect logout
            String logoutPageUrl = ssoServer.concat(Conf.SSO_LOGOUT);
            res.sendRedirect(logoutPageUrl);

            return;
        }
        String cookieSessionId = CookieUtil.getValue(req, Conf.SSO_SESSIONID);
        XxlSsoUser xxlUser = CacheManager.getData(cookieSessionId);
        if (xxlUser == null) {
            xxlUser = SsoWebLoginHelper.loginCheckRemote(ssoServer.concat(Conf.SSO_TOKEN_CHECK), req, res, domain);
        }
        if (xxlUser != null&&localCacheTime>0) {
            CacheManager.setData(cookieSessionId, xxlUser, localCacheTime);
        }
        if (xxlUser == null) {
            String header = req.getHeader("content-type");
            boolean isJson = header != null && header.contains("json");
            res.setStatus(401);
            String loginPageUrl = ssoServer.concat(Conf.SSO_LOGIN);
            res.setContentType("application/json;charset=UTF-8");
            res.getWriter().println("{\"code\":" + Conf.SSO_LOGIN_FAIL_RESULT.getCode() + ", \"msg\":\"" + Conf.SSO_LOGIN_FAIL_RESULT.getMsg() + "\",\"loginPageUrl\":\"" + loginPageUrl + "\"}");
            return;
        }
        // ser sso user
        request.setAttribute(Conf.SSO_USER, xxlUser);
        // already login, allow
        chain.doFilter(request, response);
        return;
    }

}
